package com.atguigu.mall.mallware.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.util.HashMap;

@Configuration
@Slf4j
public class MyRabbitConfig {

  @Autowired RabbitTemplate rabbitTemplate;

  @Bean
  public MessageConverter messageConverter() {
    return new Jackson2JsonMessageConverter();
  }

  @PostConstruct // MyRabbitConfig对象创建完成以后，执行这个方法
  public void initRabbitTemplate() {
    // 设置确认回调
    rabbitTemplate.setConfirmCallback(
        new RabbitTemplate.ConfirmCallback() {
          /**
           * 1、只要消息抵达Broker就ack=true
           *
           * @param correlationData 当前消息的唯一关联数据（这个是消息的唯一id）
           * @param ack 消息是否成功收到
           * @param cause 失败的原因
           */
          @Override
          public void confirm(CorrelationData correlationData, boolean ack, String cause) {
            log.info("当前消息的唯一关联数据:[{}],消息是否成功收到:[{}],失败的原因:[{}]", correlationData, ack, cause);
          }
        });

    rabbitTemplate.setReturnCallback(
        (message, replyCode, replyText, exchange, routingKey) -> {
          log.info(
              "Fail Message:[{}],replyCode:[{}],replyText:[{}],exchange:[{}],routingKey:[{}]",
              message,
              replyCode,
              replyText,
              exchange,
              routingKey);
        });
  }

  /**
   * 库存服务默认的交换机
   *
   * @return
   */
  @Bean
  public Exchange stockEventExchange() {
    // String name, boolean durable, boolean autoDelete, Map<String, Object> arguments
    TopicExchange topicExchange = new TopicExchange("stock-event-exchange", true, false);
    return topicExchange;
  }

  /**
   * 普通队列
   *
   * @return
   */
  @Bean
  public Queue stockReleaseStockQueue() {
    // String name, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object>
    // arguments
    Queue queue = new Queue("stock.release.stock.queue", true, false, false);
    return queue;
  }

  /**
   * 延迟队列
   *
   * @return
   */
  @Bean
  public Queue stockDelay() {

    HashMap<String, Object> arguments = new HashMap<>(3);
    arguments.put("x-dead-letter-exchange", "stock-event-exchange");
    arguments.put("x-dead-letter-routing-key", "stock.release");
    // 消息过期时间 2分钟
    arguments.put("x-message-ttl", 120000);

    Queue queue = new Queue("stock.delay.queue", true, false, false, arguments);
    return queue;
  }

  /**
   * 交换机与普通队列绑定
   *
   * @return
   */
  @Bean
  public Binding stockLocked() {
    // String destination, DestinationType destinationType, String exchange, String routingKey,
    // 			Map<String, Object> arguments
    Binding binding =
        new Binding(
            "stock.release.stock.queue",
            Binding.DestinationType.QUEUE,
            "stock-event-exchange",
            "stock.release.#",
            null);

    return binding;
  }

  /**
   * 交换机与延迟队列绑定
   *
   * @return
   */
  @Bean
  public Binding stockLockedBinding() {
    return new Binding(
        "stock.delay.queue",
        Binding.DestinationType.QUEUE,
        "stock-event-exchange",
        "stock.locked",
        null);
  }
}
